package org.opu.pc.domain.dao.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedHashSet;
import java.util.List;

import org.hibernate.FetchMode;
import org.hibernate.criterion.CriteriaSpecification;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.opu.pc.domain.dao.PublicationDao;
import org.opu.pc.domain.domains.Publication;
import org.opu.pc.domain.domains.Publisher;
import org.opu.pc.ui.util.Logger;

public class PublicationDaoImpl extends AbstractHibernateDao<Integer, Publication>
        implements PublicationDao, CriteriaSpecification {

    private Logger logger = Logger.create(PublicationDaoImpl.class);

    @Override
    protected Class<Publication> getDomainClass() {
        return Publication.class;
    }

    @Override
    @SuppressWarnings("unchecked")
    public List<Publication> getPublicationsByName(String name) {
        DetachedCriteria criteria = DetachedCriteria.forClass(getDomainClass());
        criteria.add(Restrictions.eq("name", name));
        List<Publication> list = hibernateTemplate.findByCriteria(criteria);
        flush();
        return list;
    }

    @Override
    @SuppressWarnings("unchecked")
    public List<Publication> searchPublicationsByName(String name, Boolean wasApplied) {
        DetachedCriteria criteria = DetachedCriteria.forClass(getDomainClass());
        criteria.add(Restrictions.like("name", name));
        if (wasApplied != null) {
            criteria.add(Restrictions.eq("wasApplied", wasApplied));
        }
        List<Publication> list = hibernateTemplate.findByCriteria(criteria);
        // hibernateTemplate.findByCriteria(criteria);
        flush();
        return list;
    }

    @Override
    public List<Publication> getPublicationsForPublisher(Publisher publicator,
            Boolean wasApplied) {
        return getPublicationsForPublisher(publicator.getId(), wasApplied);
    }

    @Override
    @SuppressWarnings("unchecked")
    public List<Publication> getPublicationsForPublisher(Integer publicatorId,
            Boolean wasApplied) {
        DetachedCriteria criteria = DetachedCriteria.forClass(getDomainClass());
        if (wasApplied != null) {
            criteria.add(Restrictions.eq("wasApplied", wasApplied));
        }
        criteria.createAlias("publishers", "publisher")
                .setFetchMode("publishers", FetchMode.JOIN);
        criteria.add(Restrictions.eq("publisher.id", publicatorId));
        
        List<Publication> list = hibernateTemplate.findByCriteria(criteria);
        //hibernateTemplate.findByCriteria(criterial);
        
        flush();
        return list;
    }

    @Override
    public List<Publication> getStudentsPublications(Date start, Date end) {

        DetachedCriteria criteria = DetachedCriteria.forClass(getDomainClass());
        criteria.add(Restrictions.between("date", start, end));
    	criteria.addOrder(Order.asc("date"));

        criteria.createAlias("publishers", "publisher")
                .setFetchMode("publishers", FetchMode.JOIN);
        criteria.add(Restrictions.eq("publisher.isStudent", Boolean.TRUE));

    	criteria.createAlias("publisher.publications", "publication", LEFT_JOIN);
        criteria.createAlias("publication.publishers", "publisher2", LEFT_JOIN);

        criteria.setResultTransformer(DetachedCriteria.DISTINCT_ROOT_ENTITY);

        List list = hibernateTemplate.findByCriteria(criteria);
        logger.debug("Get " + list.size() + " publishers (with repeat)");
        return new ArrayList<Publication>(new LinkedHashSet<Publication>(list));
    }

    @Override
    public List<Publication> getProfessorPublications(Date start, Date end,
            Integer professorId){
        DetachedCriteria criteria = DetachedCriteria.forClass(Publisher.class);
    	criteria.add(Restrictions.eq("isStudent", false));
        criteria.add(Restrictions.eq("id", professorId));

    	criteria.createAlias("publications", "publication", LEFT_JOIN);
    	criteria.add(Restrictions.between("publication.date", start, end));
    	criteria.addOrder(Order.asc("publication.date"));

    	criteria.createAlias("publication.publishers", "publisher", LEFT_JOIN);

        List<Publisher> tmpList = new ArrayList(new LinkedHashSet<Publisher>(
                hibernateTemplate.findByCriteria(criteria)));

        logger.debug("Get " + tmpList.size() + " publishers with id = " + professorId);

        if (!tmpList.isEmpty()){
            return new ArrayList(new LinkedHashSet<Publication>(tmpList.get(0).getPublications()));
        } else {
            return new ArrayList<Publication>();
        }
    }

}
